#ifndef BUBBLEFS_H
#define BUBBLEFS_H

#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <sys/stat.h>

#define NAME_LEN (256)
#define BLOCKSIZE (4096) // 4KB
#define INODENUMS (2000) // number of inodes which is number of files and dirs
#define TOTALSIZE (1UL << 25) // 32MB
#define BLOCKNUMS (TOTALSIZE / BLOCKSIZE)
#define MAGICNUM (0x40804080U)
#define INODES_PER_BLOCK (BLOCKSIZE / sizeof(struct bubblefs_inode))
#define INODE_BLOCKS (INODENUMS / INODES_PER_BLOCK)
#define FREE_MAP_BLOCKS (BLOCKNUMS / (BLOCKSIZE * 8) + 1)
#define DIR_PER_BLOCK (BLOCKSIZE / sizeof(struct dirnode))

// Helps with distinguisting the references
// from an inode and datablock
enum bubble_ref_type { EMPTY, INODE, DATABLOCK };

/**
* Reference struct for inodes
* to allow them to have variable sized files
* If a file size is > 64KB, multiple inodes can
* be used in a linked list.
* inodes will include a reference list for file
* this should only be the last node
*
*/
struct bubble_ref {
    enum bubble_ref_type btype;
    uint32_t offset; //either data block location or inode index
};

/**
* Superblock contains metadata about the filesystem.
*
* structure:
* | super block (block 0) | inodes | free_map | data blocks |
* 
*/
struct bubblefs_superblock {
    uint32_t magic;//magic number
    char name[NAME_LEN]; //filesystem name
    size_t size;//filesystem size
    uint32_t inodes_offset; //starting inodes offset
    uint32_t free_map_offset; //starting free_map
    uint32_t n_inodes; //number of inodes
    uint32_t n_blocks; //number of datablocks
};

/**
* INode, which is an index node, this
* represents a file in your system (although, further abstractions
* use dentry
* to map filenames to inodes, this is not necessary)
* This inode, contains the filename, stat information
* (permissions, creation time, user id, group id, etc).
* A critical component of the inode is references to data blocks and
* other inodes.
*/
struct bubblefs_inode {
    char used;
    char name[NAME_LEN];
    struct stat file_stat;
    size_t size;
    struct bubble_ref refs[16];
};


// dir
struct dirnode {
    uint32_t inum;
    char name[NAME_LEN];
};

#endif
